﻿using System;
using System.Collections;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using System.Xml;
using Microsoft.Win32;
using System.Threading;
using System.Drawing.Drawing2D;

namespace Typo3ImageUpload
{
    public partial class UploadWizard : Form
    {
        private ArrayList images;
        private T3Connector t3;
        private String uploadpath;
        private int actStep = 1;
        private Point stepPosition = new Point(20, 20);

        //Uploads
        private static int uploadCount;
        private static int uploadFails;
        private static ArrayList uploadThreads;

        //Context Entries
        private const string MenuName = "Folder\\shell\\NewMenuOption";
        private const string Command = "Folder\\shell\\NewMenuOption\\command";

        public UploadWizard(ArrayList images)
        {
            InitializeComponent();

            //Breite ändern!
            this.Width = 330;
            

            //Prüfen ob applikation schon läuft!
            string proc = Process.GetCurrentProcess().ProcessName;
            Process[] processes = Process.GetProcessesByName(proc);
            if (processes.Length > 1){
                MessageBox.Show("Bereits gestartet");
                //this.Visible = false;
                //return null;
            }

            //Applikation in Kontext-Menu registrieren
            String aPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
            RegistryKey regmenu = null;
            RegistryKey regcmd = null;
            try
            {
                regmenu = Registry.ClassesRoot.CreateSubKey(MenuName);
                if (regmenu != null)
                    regmenu.SetValue("", "Typo3ImageUpload");
                regcmd = Registry.ClassesRoot.CreateSubKey(Command);
                if (regcmd != null)
                    regcmd.SetValue("", aPath+" %1");
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.ToString());
            }
            finally
            {
                if (regmenu != null)
                    regmenu.Close();
                if (regcmd != null)
                    regcmd.Close();
            }        



            //Form & Vars vorbereiten
            this.images = images;
            t3tree.ImageList = treeimglist;

            lblImagesText.Text = "Ingesamt " + images.Count + " Bilder zum hochladen";

            //Settings
            loadProfiles();
        }

        private void changeStep(int dir)
        {
            if (dir > 0) {
                actStep += 1;
            }
            else if (dir < 0 && actStep > 1) {
                actStep -= 1;
            }

            //alle ausblenden
            step1.Visible = false;
            step2.Visible = false;
            step3.Visible = false;

            //aktuellen Step einblenden
            switch (actStep) { 
                case 3:
                    step3.Location = stepPosition;
                    step3.Visible = true;
                    break;
                case 2:
                    step2.Location = stepPosition;
                    step2.Visible = true;
                    break;
                default:
                    step1.Location = stepPosition;
                    step1.Visible = true;
                    break;
            }

        }
        /// <summary>
        /// Profile aus den Settings holen und im GUI laden.
        /// Sind mehrere Profile vorhanden, wird die Auswahlbox angezeigt, zum anzeigen dieser.
        /// Ansonsten wird das eine Profil gesetzt.
        /// </summary>
        private void loadProfiles()
        {
            ArrayList prof = Properties.Settings.Default.t3_profiles;
            String temps;
            cbProfiles.Visible = false;
            btnDelProfile.Visible = false;
            //Alle entfernen
            cbProfiles.DataSource = null;
            if (prof!=null && prof.Count > 1)
            {
                cbProfiles.Visible = true;
                btnDelProfile.Visible = true;
                cbProfiles.DataSource = prof;
            }
            if (prof != null && prof.Count > 0)
            {
                temps = (String)prof[0];
                txtpath.Text = temps.Substring(0, temps.IndexOf(", "));
                txtuser.Text = temps.Substring(temps.IndexOf(", ")+2);
            }
        }

        private void ConvertXmlNodeToTreeNode(XmlNode xmlNode, TreeNodeCollection treeNodes)
        {
            
            switch (xmlNode.NodeType)
            {
                case XmlNodeType.ProcessingInstruction:
                case XmlNodeType.XmlDeclaration:
                    //newTreeNode.Text = "<?" + xmlNode.Name + " " +xmlNode.Value + "?>";
                    break;
                case XmlNodeType.Element:
                    TreeNode newTreeNode = treeNodes.Add(xmlNode.Name);
                    newTreeNode.ImageIndex = 0;
                    newTreeNode.SelectedImageIndex = 1;
                    foreach (XmlNode childNode in xmlNode.ChildNodes)
                    {
                        ConvertXmlNodeToTreeNode(childNode, newTreeNode.Nodes);
                    }
                    break;
                case XmlNodeType.Attribute:
                    //newTreeNode.Text = "ATTRIBUTE: " + xmlNode.Name;
                    break;
                case XmlNodeType.Text:
                case XmlNodeType.CDATA:
                    //newTreeNode.Text = xmlNode.Value;
                    break;
                case XmlNodeType.Comment:
                    // newTreeNode.Text = "<!--" + xmlNode.Value + "-->";
                    break;
            }

            /*if (xmlNode.Attributes != null)
            {
                foreach (XmlAttribute attribute in xmlNode.Attributes)
                {
                    ConvertXmlNodeToTreeNode(attribute, newTreeNode.Nodes);
                }
            }*/
            
        }

        private void fillTree()
        {
            //clear tree
            foreach(TreeNode n in t3tree.Nodes){
                n.Remove();
            }
            
            //Load and set
            try
            {
                //Konnektor starten und anmelden
                t3 = new T3Connector(txtpath.Text, txtuser.Text, txtpass.Text);

                String xmlfm = t3.getFilemounts();
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(xmlfm);
                ConvertXmlNodeToTreeNode(doc.FirstChild, t3tree.Nodes);

                t3tree.Enabled = true;
                t3tree.Nodes[0].Expand();
            }
            catch (T3Exception ex)
            {
                MessageBox.Show(ex.Message);
                throw new Exception(ex.Message);
            }
            catch (Exception ex)
            {
                lblstatus.Text = "Fehler: " + ex.Message;
                throw new Exception(ex.Message);
            }
        }

        private void saveUserData(String path, String user)
        {
            //Properties.Settings.Default.t3_web = path;
            //Properties.Settings.Default.t3_user = user;
            bool exist = false;
            ArrayList al = Properties.Settings.Default.t3_profiles;
            if (al == null){
                al = new ArrayList();
            }

            foreach (String s in al)
            {
                if (s.Equals(path + ", " + user))
                {
                    exist = true;
                }
            }
            
            if (!exist)
            {
                al.Add(path + ", " + user);
                Properties.Settings.Default.t3_profiles = al;
                Properties.Settings.Default.Save();
                loadProfiles();
            }
        }

        private void setUploadPath(TreeNode node)
        {
            String mpath = "";

            do
            {
                mpath = node.Text+"/"+mpath;
                node.ImageIndex = 0;
                node = node.Parent;
            } while (node != null);

            uploadpath = mpath;
        }

        private void uploadImages()
        {
            this.Cursor = Cursors.WaitCursor;
            btnupload.Enabled = false;

            //Progress
            progressBar1.Visible = true;
            progressBar1.Minimum = 0;
            progressBar1.Maximum = images.Count;
            progressBar1.Value = 0;
            progressBar1.Step = 1;

            //Size
            int w = 800;
            int h = 600;
            if (imgres_1024.Checked) {
                w = 1024;
                h = 786;
            }
            else if (imgres_800.Checked) {
                w = 800;
                h = 600;
            }

            //Tempdir
            String tempPath = Environment.GetEnvironmentVariable("TEMP");
            String targetPath;
            Random random = new Random();
            do{
                targetPath = tempPath+"\\t3upimg"+random.Next(1000, 9999).ToString();
            }while(Directory.Exists(targetPath));
            Console.WriteLine("DIR:" + targetPath);
            Directory.CreateDirectory(targetPath);

            uploadCount = uploadFails = 0;
            uploadThreads = null;
            uploadThreads = new ArrayList();

            UploadThread tmpUPT;
            Thread tmpThread;
            foreach (String i in images)
            {
                tmpUPT = new UploadThread(this);
                tmpUPT.image = i;
                tmpUPT.newH = h;
                tmpUPT.newW = w;
                tmpUPT.tempPath = targetPath;
                tmpUPT.uploadPath = uploadpath;
                tmpThread = new Thread(new ThreadStart(tmpUPT.upload));
                uploadThreads.Add(tmpThread);
                tmpThread.Start();
            }
            /*
            //RESIZE
            ArrayList upImages = new ArrayList();
            Image tmpImage;
            String targetFile;
            //Thread[] ta = new Thread[upImages.Count]; // Thread-Array
            //int ti = 0;
            foreach (String i in images)
            {
                try
                {
                    tmpImage = Image.FromFile(i);
                    tmpImage = Form2.ResizePic(tmpImage, w, h, true, Color.Transparent, -1, -1);

                    targetFile = targetPath + "\\" + i.Substring(i.LastIndexOf('\\'));
                    tmpImage.Save(targetFile);
                    tmpImage.Dispose();
                    upImages.Add(targetFile);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                finally {
                    tmpImage = null;
                    GC.Collect();
                    progressBar1.PerformStep();
                }
            }
            progressBar1.Maximum = images.Count+upImages.Count;

            //UPLOAD
            foreach (String i in upImages)
            {

                try{
                    t3.uploadImage(uploadpath, i);
                    Console.WriteLine("OK: " + i);
                }
                catch(Exception e)
                {
                    Console.WriteLine(e.Message+": " + i);
                }
                finally{
                    progressBar1.PerformStep();
                    Thread.Sleep(50);
                }
            } 

            this.Cursor = Cursors.Default;
            progressBar1.Visible = false;
            //btnupload.Enabled = true;
             */
        }

        private void refreshUploadStat(bool success)
        {
            if (!success) {
                uploadFails++;
            }
            uploadCount++;
            progressBar1.PerformStep();

            //fertig?
            if (uploadCount >= uploadThreads.Count) {
                this.Cursor = Cursors.Default;
                progressBar1.Visible = false;
                btnupload.Enabled = true;
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                this.fillTree();
                saveUserData(txtpath.Text, txtuser.Text);
                changeStep(+1);
            }
            catch (Exception ex) {
                Console.WriteLine(ex.Message);
            }
            
        }

        private void button2_Click(object sender, EventArgs e)
        {
            this.Dispose();
        }

//        private void t3tree_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        private void t3tree_AfterSelect(object sender, TreeViewEventArgs e)
        {
            setUploadPath(e.Node);
            lblstatus.Text = "Neuer Pfad:" + uploadpath;

            if (uploadpath.Equals(""))
            {
                btnupload.Enabled = false;
            }
            else {
                btnupload.Enabled = true;
            }
        }

        private void t3tree_MouseClick(object sender, MouseEventArgs e)
        {
            TreeNode n = t3tree.GetNodeAt(e.X, e.Y);
            if (n != null) {
                setUploadPath(n);
                t3tree.SelectedNode = n;
            }
            
        }


        private void cbProfiles_ValueMemberChanged(object sender, EventArgs e)
        {
            String s = cbProfiles.SelectedText;
            txtpath.Text = s.Substring(0,s.IndexOf(", "));
            txtuser.Text = s.Substring(s.IndexOf(", ")+2);
        }

        private void btnDelProfile_Click(object sender, EventArgs e)
        {
            ArrayList al = Properties.Settings.Default.t3_profiles;
            for(int i=0;i<al.Count;i++) {
                if (al[i].Equals(cbProfiles.Text)) {
                    al.RemoveAt(i);
                    Properties.Settings.Default.t3_profiles = al;
                    Properties.Settings.Default.Save();;
                }
            }
            loadProfiles();
        }

        private void neuesVerzeichnisToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (t3tree.SelectedNode != null)
            {
                t3tree.LabelEdit = true;
                TreeNode newNode = t3tree.SelectedNode.Nodes.Add("");
                newNode.ImageIndex = 0;
                newNode.SelectedImageIndex = 1;
                t3tree.SelectedNode.Expand();
                newNode.BeginEdit();
            }
        }


        private void button4_Click_1(object sender, EventArgs e)
        {
            changeStep(+1);
        }

        private void button3_Click(object sender, EventArgs e)
        {
            changeStep(-1);
        }

        private void cbProfiles_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void cbProfiles_SelectedIndexChanged(object sender, EventArgs e)
        {
            //Werte setzen
            String s = cbProfiles.Text;
            if (!s.Equals(""))
            {
                txtpath.Text = s.Substring(0, s.IndexOf(", "));
                txtuser.Text = s.Substring(s.IndexOf(", ") + 2);
            }
        }

        private void btnupload_Click_1(object sender, EventArgs e)
        {
            uploadImages();
        }

        private void UploadWizard_FormClosed(object sender, FormClosedEventArgs e)
        {
            try
            {
                RegistryKey reg = Registry.ClassesRoot.OpenSubKey(Command);
                if (reg != null)
                {
                    reg.Close();
                    Registry.ClassesRoot.DeleteSubKey(Command);
                }
                reg = Registry.ClassesRoot.OpenSubKey(MenuName);
                if (reg != null)
                {
                    reg.Close();
                    Registry.ClassesRoot.DeleteSubKey(MenuName);
                    
                }

                //Alle UploadThreads stoppen
                foreach (Thread t in uploadThreads) {
                    t.Abort();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.ToString());
            }

        }

        private void t3tree_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            //MessageBox.Show(e.Node.Text + " Edited!");
            //Prüfen ob noch leer
            if (e.Label == null) {
                //MessageBox.Show("Bitte Verzeichnisnamen angeben");
                //e.Node.BeginEdit();
                e.Node.EndEdit(true);
                e.Node.Remove();
                return;
            }
            if (e.Label.Equals(e.Node.Text)) {
                e.Node.EndEdit(true);
                return;
            }
            //Prüfen ob ungültige zeichen
            if (e.Label.IndexOfAny(Path.GetInvalidPathChars()) != -1) {
                MessageBox.Show("Ungültige Zeichen in Namen");
                e.CancelEdit = true;
                e.Node.BeginEdit();
                return;
            }
            /*foreach(Char s in Path.GetInvalidPathChars()){
                if(e.Label.Contains(s.ToString())){
                MessageBox.Show("Ungültige Zeichen in Namen");
                e.Node.EndEdit(true);
                e.Node.Text = "";
                e.Node.BeginEdit();
                return;
                }
            }*/
            
            //Prüfen ob Verzeichnis schon vorhanden
            foreach (TreeNode n in e.Node.Parent.Nodes) {
                if (n != e.Node && n.Text.Equals(e.Label))
                {
                    MessageBox.Show("Verzeichnisname bereits benutzt. Bitte anderen eingeben");
                    e.CancelEdit = true;
                    e.Node.BeginEdit();
                    return;
                }
            }


            //Alles OK
            e.Node.EndEdit(false);
            t3tree.LabelEdit = false;


                //T3 senden
            try
            {
                t3.changeDir(e.Node.Parent.FullPath,e.Label,e.Node.Text);
                
            }
            catch (T3Exception ex) {
                MessageBox.Show(ex.Message);
            }
            catch (Exception ex) {
                Console.WriteLine(ex.Message);

                //Node löschen ! Fehler
                e.Node.EndEdit(true);
                e.Node.Remove();
                MessageBox.Show("Fehler beim anlegen");
            }
            
  
            
        }

        private void verzeichnisLöschenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (t3tree.SelectedNode != null)
            {
                //MessageBox.Show("Neues Verzeichnis unter <b>" + t3tree.SelectedNode.Text + "</b> anlegen");
                t3tree.LabelEdit = true;
                t3tree.SelectedNode.BeginEdit();
            }
        }

        class UploadThread
        {
            private UploadWizard parent;

            public static int i = 0;
            public String image { set; get; }
            public int newW { set; get; }
            public int newH { set; get; }
            public String tempPath { set; get; }
            public String uploadPath { set; get; }

            public static Object lockvar = ""; // Lock-Variable
  
            public UploadThread(UploadWizard p)
            {
                parent = p;
            }

            public void upload()
            {
                Image newImage;
                Image tmpImage;
                bool success = false;
                

                try
                {
                    //Nur Bilder die existieren
                    if (!File.Exists(image)) { throw new Exception("not found"); } 
                    
                    //Bild laden
                    tmpImage = Image.FromFile(image);

                    //Exif-Werte
                    //...

                    //aus alter Grösse mit MAX-Werten, grösse berechnen (Verhältnis)
                    int oldW = tmpImage.Width;
                    int oldH = tmpImage.Height;
                    if (oldW >= oldH && oldW > newW)
                    { //aus breite
                        newH = (int) Math.Round((newW / (double) oldW) * oldH);
                    }
                    else if (oldH > newH)
                    {
                        newW = (int) Math.Round((newH / (double)oldH) * oldW);
                    }
                    else
                    {
                        newH = oldH;
                        newW = oldW;
                    }


                    //tmpImage = Form2.ResizePic(tmpImage, newW, newH, true, Color.Transparent, -1, -1);
                    newImage = new Bitmap(newW, newH);
                    using (Graphics gr = Graphics.FromImage(newImage))
                    {
                        gr.SmoothingMode = SmoothingMode.AntiAlias;
                        gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
                        gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
                        gr.DrawImage(tmpImage, new Rectangle(0, 0, newW, newH));
                    }

                    //Neues Bild speichern in Tempverzeichnis
                    String targetFile = tempPath + "\\" + image.Substring(image.LastIndexOf('\\'));
                    newImage.Save(targetFile);
                    tmpImage.Dispose();
                    newImage.Dispose();

                    //Per T3Connector hochladen (Monitor, damit immer nur einer hochlädt)
                    Monitor.Enter(lockvar);
                    T3Connector.getInstance().uploadImage(uploadPath, targetFile);
                    Console.WriteLine("OK: " + targetFile);
                    Monitor.Exit(lockvar);

                    //OK
                    success = true;

                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                finally
                {
                    //melden
                    this.parent.refreshUploadStat(success);
                   

                    //aufräumen
                    tmpImage = null;
                    newImage = null;
                    GC.Collect();
                }


            }

        }


    }

    
}
